package org.budo.jdbc.driver.resultset.impl;

import java.io.InputStream;
import java.io.Reader;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.budo.jdbc.driver.AbstractBudoJdbcResultSet;
import org.budo.support.lang.util.BooleanUtil;
import org.budo.support.lang.util.IoUtil;
import org.budo.support.lang.util.NumberUtil;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * @author lmw
 */
@Getter
@Setter
@Accessors(fluent = true)
public abstract class AbstractArrayResultSet<T> extends AbstractBudoJdbcResultSet {
    private ResultSetMetaData metaData;

    private boolean lastValueWasNull = false;

    private T[] valueArray;

    private int rowNumber = -1;

    @Override
    public ResultSetMetaData getMetaData() throws SQLException {
        if (null == this.metaData) {
            throw new SQLException("#25 metaData is null, this=" + this);
        }

        return this.metaData;
    }

    @Override
    public boolean next() throws SQLException {
        if (null == this.valueArray() //
                || this.valueArray().length <= this.rowNumber + 1) {
            return false;
        }

        this.rowNumber++;
        return true;
    }

    /**
     * 获取原始值
     */
    protected abstract Object getCellValue(String columnLabel) throws SQLException;

    private Object getCellValue(int columnIndex) throws SQLException {
        ResultSetMetaData metaData = this.getMetaData();
        String columnLabel = metaData.getColumnLabel(columnIndex);
        return this.getCellValue(columnLabel);
    }

    @Override
    public Object getObject(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);

        if (null != value && value instanceof byte[]) {
            return new String((byte[]) value);
        }

        return value;
    }

    @Override
    public Object getObject(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);

        if (null != value && value instanceof byte[]) {
            return new String((byte[]) value);
        }

        return value;
    }

    @Override
    public String getString(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toString(value);
    }

    @Override
    public String getString(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toString(value);
    }

    @Override
    public int getInt(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return NumberUtil.toInteger(value);
    }

    @Override
    public int getInt(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return NumberUtil.toInteger(value);
    }

    @Override
    public boolean getBoolean(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return BooleanUtil.toBoolean(value);
    }

    @Override
    public boolean getBoolean(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return BooleanUtil.toBoolean(value);
    }

    @Override
    public byte[] getBytes(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toByteArray(value);
    }

    @Override
    public byte[] getBytes(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toByteArray(value);
    }

    @Override
    public InputStream getAsciiStream(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toInputStream(value);
    }

    @Override
    public InputStream getAsciiStream(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toInputStream(value);
    }

    @Override
    public InputStream getBinaryStream(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toInputStream(value);
    }

    @Override
    public InputStream getBinaryStream(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toInputStream(value);
    }

    @Override
    public Reader getCharacterStream(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toReader(value);
    }

    @Override
    public Reader getCharacterStream(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toReader(value);
    }

    @Override
    public Reader getNCharacterStream(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toReader(value);
    }

    @Override
    public Reader getNCharacterStream(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toReader(value);
    }

    @Override
    public InputStream getUnicodeStream(int columnIndex) throws SQLException {
        Object value = this.getCellValue(columnIndex);
        return IoUtil.toInputStream(value);
    }

    @Override
    public InputStream getUnicodeStream(String columnLabel) throws SQLException {
        Object value = this.getCellValue(columnLabel);
        return IoUtil.toInputStream(value);
    }
}
